Rotate ad creatives with the Select URL API

Use the Select URL API to take advantage of Shared Storage to determine what creative a user sees across sites.

An advertiser or a content producer may want to apply different content rotation strategies to a campaign, and rotate the contents or creatives to increase effectiveness. The Select URL API can be used to run different rotation strategies, such as sequential rotation and evenly-distributed rotation, across different sites.

With Select URL API creative rotation, you can store data, such as creative ID, view counts, and user interaction to determine which creative users see across different sites.

For more information on the underlying API and how selection works, explore the Select URL API documentation.

Try creative rotation

To experiment with creative rotation, make sure Select URL API and Shared Storage are enabled:

  • In chrome://settings/content/siteData, select Allow sites to save data on your device or Delete data sites have saved to your device when you close all windows.
  • In chrome://settings/adPrivacy/sites, select Site-suggested ads.

Try our Shared Storage live demo for a live version of the code samples in this document.

Demo with code samples

In this example:

  • creative-rotation.js is the third-party script defining the content to be rotated, along with any data that determines the next content to select and display, such as weights in this example. The publisher page executes this script. This script calls shared storage worklet to determine which content to display based on available data in storage and the list of URLs to select from.

  • creative-rotation-worklet.js is the third-party's shared storage worklet that looks up the rotation strategy, calculates what content to publish next, and returns that piece of content.

How the demo works

  1. When a user visits the publisher page, the page loads the third-party's creative-rotation.js script. The creative rotation script is responsible for loading and running the shared storage worklet. The script supplies the worklet call with a list of URLs to select from.
  2. In the worklet, if shared storage hasn't been initialized yet, the storage is initialized with the initial creative rotation strategy and creative index. The initial rotation strategy used in this demo is sequential strategy.
  3. The worklet reads the rotation mode from shared storage and returns the index of the next ad. In the case of sequential rotation mode, it also updates the creative index in shared storage with the new value to be used for the next call.The worklet returns a FencedFrameConfig or opaque URN object based on the resolveToConfig value used when calling selectURL.
  4. The creative-rotation script displays the selected ad in a Fenced Frame or an iframe. See the render an ad document for details on return types.
  5. When a user changes the rotation mode, the shared storage worklet updates the creative rotation mode value stored in shared storage.
  6. When reloading the publisher page, steps 1-4 are repeated enabling the selection of the next ad to be viewed based on the selected rotation strategy

Code samples

The following are the code samples for creative-rotation.js and creative-rotation-worklet.js.

creative-rotation.js

const contentProducerUrl = 'https://your-server.example';

// Ad config with the URL of the ad, a probability weight for rotation, and the clickthrough rate.
const DEMO_AD_CONFIG = [
  {
    url: `${contentProducerUrl}/ads/ad-1.html`,
    weight: 0.7,
  },
  {
    url: `${contentProducerUrl}/ads/ad-2.html`,
    weight: 0.2,
  },
  {
    url: `${contentProducerUrl}/ads/ad-3.html`,
    weight: 0.1,
  },
];

async function setRotationMode(rotationMode) {
  // Load the worklet module
  const creativeRotationWorklet = await window.sharedStorage.createWorklet(
    `${contentProducerUrl}/url-selection/creative-rotation-worklet.js`,
    { dataOrigin: 'script-origin' }
  );

  await creativeRotationWorklet.run('set-rotation-mode', {
    data: { rotationMode }
  });
  console.log(`creative rotation mode set to ${rotationMode}`);
}

async function injectAd() {
  // Load the worklet module
  const creativeRotationWorklet = await window.sharedStorage.createWorklet(
    `${contentProducerUrl}/url-selection/creative-rotation-worklet.js`,
    { dataOrigin: 'script-origin' }
  );

  const urls = DEMO_AD_CONFIG.map(({ url }) => ({ url }));

  // Resolve the selectURL call to a fenced frame config only when it exists on the page
  const resolveToConfig = typeof window.FencedFrameConfig !== 'undefined';

  // Run the URL selection operation to determine the next ad that should be rendered
  const selectedUrl = await creativeRotationWorklet.selectURL('creative-rotation', urls, {
    data: DEMO_AD_CONFIG,
    resolveToConfig
  });

  const adSlot = document.getElementById('ad-slot');

  if (resolveToConfig && selectedUrl instanceof FencedFrameConfig) {
    adSlot.config = selectedUrl;
  } else {
    adSlot.src = selectedUrl;
  }
}

injectAd();

creative-rotation-worklet.js

class SelectURLOperation {
  async run(urls, data) {
    // Initially set the storage to sequential mode for the demo
    await SelectURLOperation.seedStorage();

    // Read the rotation mode from Shared Storage
    const rotationMode = await sharedStorage.get('creative-rotation-mode');

    // Generate a random number to be used for rotation
    const randomNumber = Math.random();

    let index;

    switch (rotationMode) {
      /**
       * Sequential rotation
       * - Rotates the creatives in order
       * - Example: A -> B -> C -> A ...
       */
      case 'sequential':
        const currentIndex = await sharedStorage.get('creative-rotation-index');
        index = parseInt(currentIndex, 10);
        const nextIndex = (index + 1) % urls.length;

        console.log(`index = ${index} / next index = ${nextIndex}`);

        await sharedStorage.set('creative-rotation-index', nextIndex.toString());
        break;

      /**
       * Evenly-distributed rotation
       * - Rotates the creatives with equal probability
       * - Example: A=33% / B=33% / C=33%
       */
      case 'even-distribution':
        index = Math.floor(randomNumber * urls.length);
        break;

      /**
       * Weighted rotation
       * - Rotates the creatives with weighted probability
       * - Example: A=70% / B=20% / C=10%
       */
      case 'weighted-distribution':
        console.log('data = ', JSON.stringify(data));
        // Find the first URL where the cumnulative sum of the weights
        // exceed the random number. The array is sorted by the weight
        // in descending order.
        let weightSum = 0;
        const { url } = data
          .sort((a, b) => b.weight - a.weight)
          .find(({ weight }) => {
            weightSum += weight;
            return weightSum > randomNumber;
          });

        index = urls.indexOf(url);
        break;

      default:
        index = 0;
    }

    console.log(JSON.stringify({ index, randomNumber, rotationMode }));
    return index;
  }

  // Set the mode to sequential and set the starting index to 0.
  static async seedStorage() {
    await sharedStorage.set('creative-rotation-mode', 'sequential', {
      ignoreIfPresent: true,
    });

    await sharedStorage.set('creative-rotation-index', 0, {
      ignoreIfPresent: true,
    });
  }
}

class SetRotationModeOperation {
  async run({ rotationMode }) {
    await sharedStorage.set('creative-rotation-mode', rotationMode);
  }
}

// Register the operation as 'creative-rotation'
register('creative-rotation', SelectURLOperation);
register('set-rotation-mode', SetRotationModeOperation);

Walkthrough with screenshots

  1. To access the Creatives Rotation using Select URL API and Shared storage, go to https://shared-storage-demo.web.app/. Choose 'Creative Rotation' demo.

  2. Choose to explore the demo as 'Publisher A'. You will be redirected to https://shared-storage-demo-publisher-a.web.app/creative-rotation. The page loads numbered content based on the creative rotation data saved in Shared Storage, accessed through the Select URL API. The demo modes for creative rotation are sequential, even distribution and weighted distribution. The worklet executes the logic to select the content that appears in the iframe. The following image shows the publisher page. A screenshot showing the contents of the page for Publisher A https://shared-storage-demo-publisher-a.web.app/creative-rotation containing an iframe with an image of the number 1, controls to choose the creative rotation strategies sequential, even distribution and weighted distribution. There is also a text area describing the different creative rotation strategies and links to the iframe and worklet logics.

    A screenshot shows the Publisher A page with an image of the number 1 and controls to choose creative rotation strategies.

  3. To view what is stored in Shared Storage, navigate to Application -> Shared Storage in Chrome DevTools. Two entries are created for shared storage. An empty storage is available for the https://shared-storage-demo-publisher-a.web.app origin. This will contain storage specific to that origin and will remain empty for our demo since the publisher does not need to write to shared storage. Note that a similar storage will be created for Publisher B when you visit that page at a later time for the demo. A screenshot showing Chrome DevTools specifically the Application section, Highlighting the Shared Storage entries and showing the empty storage for the origin of "Publisher A" https://shared-storage-demo-publisher-a.web.app

    Chrome DevTools shows empty Shared Storage for Publisher A.

  4. Another Shared Storage entry will be created for the https://shared-storage-demo-content-producer.web.app origin. This is the storage of the third-party iframe embedded on the publisher page. This storage will be used to share data between the two available publishers to coordinate creative selection. This shared storage will be used to save information about the shown creative and rotation strategy by saving two key-value pairs. The first key used in the demo is creative-rotation-index whose value is the current creative index in sequential mode. The second key is creative-rotation-mode which dictates the rotation strategy used. A screenshot showing the chrome Devtools specifically the shared storage for the origin https://shared-storage-demo-content-producer.web.app. The storage is not empty showing two key value pairs saved. The first key is creative-rotation-index with the value 1. The second saved key is creative-rotation-mode with the value "sequential"

    A screenshot shows the Chrome DevTools shared storage with two key-value pairs: creative-rotation-index: 1 and creative-rotation-mode: "sequential."

  5. Refreshing the page while in sequential mode will result in showing the next creative in the sequence 1, 2, 3, 1, …, The value for the key creative-rotation-index will change according to the index of the shown creative while in sequential mode. A screenshot showing the "Publisher A" webpage as well as the DevTools showing the Shared Storage section. The creative on the page is labelled as 2 while also the value for the key creative-rotation-index is highlighted as 2 matching the index of the creative shown. The current creative-rotation-mode is shown as sequential.

    A screenshot shows Publisher A's webpage and DevTools. The creative shown is 2, creative-rotation-mode is sequential, and creative-rotation-index is 2.

  6. Changing the creative rotation mode using the control buttons will update the value for key creative-rotation-mode into the corresponding strategy. This will be used by the worklet code to choose the next creative to be shown in the iframe. Note that the value saved for creative-rotation-index doesn"t change for rotation modes other than sequential. A screenshot showing the "Publisher A" webpage as well as the DevTools showing the Shared Storage section. The creative on the page is shown as 1. While highlighting that the creative-rotation-mode is set as weighted distribution and the corresponding control to set the rotation mode as weighted distribution is highlighted. The value for creative-rotation-index is 2 although the creative shown is 1 as the index is not used or updated for rotation modes other than sequential.

    A screenshot shows Publisher A's webpage and DevTools. The creative shown is 1, creative-rotation-mode is weighted distribution, and creative-rotation-index is 2 (unused).

  7. Navigate to the page for "Publisher B" at https://shared-storage-demo-publisher-b.web.app/creative-rotation. In sequential mode the creative shown should be the next creative in the sequence shown when visiting the URL for "Publisher A". Inspecting the Shared Storage for the content producer, you can find that both "Publisher A" and "Publisher B" share the same storage and are using the settings there to select the next creative to show and the rotation strategy to use. A screenshot showing the "Publisher B" webpage as well as the DevTools showing the Shared Storage section for the origin https://shared-storage-demo-content-producer.web.app. The creative on the page is shown as 3. While the highlighted creative-rotation index is 3 and creative-rotation-mode is sequential.

    Publisher B's webpage and DevTools. The Shared Storage creative is 3, the creative-rotation index is 3, and the creative-rotation-mode is sequential.

  8. The Shared Storage for "Publisher B" is empty, similar to "Publisher A"'s Shared Storage.  screenshot showing Chrome DevTools specifically the Application section, Highlighting the Shared Storage entries and showing the empty storage for the Origin of "Publisher B" https://shared-storage-demo-publisher-b.web.app.

    Chrome DevTools showing empty Shared Storage for Publisher B origin.

    Use cases

    All available use cases for Select URL API can be found in this section. We'll continue to add examples as we receive feedback and discover new test cases.

Engage and share feedback

Note that the Select URL API proposal is under active discussion and development and subject to change.

We're eager to hear your thoughts on the Select URL API.

Stay Informed

  • Mailing List: Subscribe to our mailing list for the latest updates and announcements related to the Select URL and Shared Storage APIs.

Need Help?